package com.timber.login;


import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;

import com.timber.util.Global;
import com.timber.util.SLDatabaseProperties;
import com.timber.util.SLMessage;
import com.timber.util.Util;


/**
 *	class to manage login process
 */
public class LoginMgr extends Global
{
  /**
   *	login with  as application
   */
  public static boolean doInvolvedLogin()
  {
    return doInvolvedLogin( "IDELTA" );
  }

  /**
   *	display login dialog, get name / password
   *	login into database, assuming PRIMARY server URL set in the etc/.properties file
   */
  public static boolean doInvolvedLogin( String appName )
  {
    SLUserDBSQL mgr = new SLUserDBSQL();
    LoginDialog login = new LoginDialog();
    login.setModal( true );

    int loginCnt = 0;
    //	give it five attempts
    while( loginCnt++ < 5 )
    {
      //	display login dialog
      login.setVisible( true );
      if( login.getActionCode() == LoginDialog.CANCEL )
        return false;
      try
      {
	// login to PRIMARY dataserver
        setUserName( login.getUserName() );
        setPassword( login.getPassword() );
        setAppName( appName );

        if( doLoginWithRetry( Global.PRIMARY ) == false )
          continue;

        if( getDBConnection( PRIMARY ) != null )
        {
          if( login.getActionCode() == LoginDialog.CHANGE_PWD )
          {
            if( !changePassword( login.getPassword() ) )
              continue;
            else
              break;
          }

          // DAW 2Aug2004 - If IMS User we have successfully logged in
          //                with plain text password which we must now encrypt.

          if( getAppComponent( "IMS_USER" ) && IMSPasswordChange )
          {
            Util.log( "Perform specific processing for IMS user" );

            Connection conn;
            String plainTextPassword, encryptedPassword;
            plainTextPassword = dbProperties.getProperty(SLDatabaseProperties.PASSWORD);
            encryptedPassword = encryptString( dbProperties.getProperty( SLDatabaseProperties.PASSWORD ) );

	    //setPassword( encryptedPassword );
	    //	close existing connection to PRIMARY, re-open with encrypted password
            getDBConnection( PRIMARY ).close();
            conn = getDBConnection( PRIMARY );
            Util.log( "IMS User: Changing password on PRIMARY to encrypted version");
            Util.debug( "IMS User: Changing password on PRIMARY from " +
                      dbProperties.getProperty( "password" ) + " to " + encryptedPassword );

            SLUserDBSQL.changePassword( conn, dbProperties.getProperty( SLDatabaseProperties.PASSWORD),
                                        encryptedPassword, false );

            Util.log( "IMS User: Password successfully changed to encrypted version on PRIMARY" );

            if( !primaryDbProp.getUrl().equals( secondaryDbProp.getUrl() ) )
            {
              useEncryption = false; // Connect to secondary with plain text password
              conn = getDBConnection( SECONDARY );
              Util.log( "IMS User: Changing password on SECONDARY to encrypted version");
              Util.debug( "IMS User: Changing password on SECONDARY from " +
                        dbProperties.getProperty( "password" ) + " to " + encryptedPassword );
              SLUserDBSQL.changePassword( conn, dbProperties.getProperty( "password" ),
                                          encryptedPassword, false );

              Util.log( "IMS User: Password successfully changed to encrypted version on SECONDARY" );
            }

            // Set password change flag back so that we don't change it more than once
            // after initial login.

            IMSPasswordChange = false;
            setPassword( encryptedPassword );
            Global.setPassword( encryptedPassword );
          }

          if( Global.getSingleWks() != null && Global.getSingleWks().toUpperCase().equals( "OFF" ) ) //Do not perform iDelta security check
            return true;

	  String lastLogin = mgr.verifyLogin( getDBConnection( PRIMARY ), true );
          LoginConfirmation conf = new LoginConfirmation( lastLogin );
          conf.setModal( true );
          conf.setVisible( true );

          return true;
        }
      }
      catch( SLLoginException ex )
      {

        if( ( ex.errCode == 1 ) || ( ex.errCode == 2 ) )
        {
          SLMessage.Error( null, ex, "doInvolvedLogin", ex.getMessage() );
          if( !changePassword( login.getPassword() ) )
            continue;
          else
            break;
        }
        else if( ex.errCode == 3 )
        {
          SLMessage.Error( null, ex, "doInvolvedLogin", ex.getMessage() );
          try
          {
            getDBConnection( PRIMARY ).close();
          }
          catch( Exception e )
          {
            SLMessage.Error( null, e, "doInvolvedLogin" );
          }
        }
        else
        {
          SLMessage.Error( null, ex, "doInvolvedLogin", ex.getMessage() );

          try
          {
            getDBConnection( PRIMARY ).close();
          }
          catch( Exception e )
          {
            SLMessage.Error( null, e, "doInvolvedLogin" );
          }
        }
      }

      catch( Exception ex )
      {
        SLMessage.Error( null, ex, "doInvolvedLogin", "Error during login" );
        try
        {
          getDBConnection( PRIMARY ).close();
        }
        catch( Exception e )
        {
          SLMessage.Error( null, e, "doInvolvedLogin" );
        }
      }
    }

    return false;
  }

/**
   *
   *	Set up PRIMARY database connection
   *
   *	@param login	dabase login
   *	@param pass	password
   *	@param appName	application name
   *
   *	uses primary URL in Global.
   *	Can be set using dbProperties in Global to pass paramaters to Sybase driver.
   */
  public static void doLogin( String uname, String pwd, String appName ) throws Exception //, ClassNotFoundException, SQLException
  {

    //	set up PRIMARY parameters.
    setUserName( uname );
    setPassword( pwd );
    setAppName( appName );

    getDBConnection( Global.PRIMARY );
  }

  /**
   * login into primary database, use user / password / appName settings in Global
   */
  public static void doLogin()
  {
    try
    {
      doLogin( getUserName(), getPassword(), getAppName() );
      doPostLogin();
    }
    catch( ClassNotFoundException e )
    {
      //  If we catch this exception - most likely our CLASSPATH is not
      //  set up correctly. This is fatal and uncorrectable while the
      //  app is running - so just exit after popping up the error box.
      SLMessage.Error( null, "Sybase classes not found." +
                       "\nCheck CLASSPATH and restart." );
      exit();
    }
    catch( SQLException e )
    {
      //  If we catch this exception - most likely our user name and/or password
      //  and/or dbUrl is wrong or missing. This is fatal so give user an error
      //  popup and exit.
      SLMessage.Error( null, e, "Login failed for user:\n<" +
                       ( ( getUserName() == null ) ? "null" : getUserName() ) + ">\n" +
                       "Letters in passwords must be typed using the correct case.\n" +
                       "Make sure that Caps Lock is not accidentally on." );

      if( Global.getSingleWks() != null )
        exit();
    }
    catch( Exception e )
    {
    }

  }


  /**
   * login into database server based on settings in Global - retrying if wrong password
   *
   * @param dbSource	logical server name
   *
   */
  public static boolean doLoginWithRetry( String dbSource )
  {
    try
    {
      String plainTextPassword;
      String encryptedPassword;

      getDBConnection( dbSource );

      doPostLogin();

      return true;
    }
    catch( ClassNotFoundException e )
    {
      //  If we catch this exception - most likely our CLASSPATH is not
      //  set up correctly. This is fatal and uncorrectable while the
      //  app is running - so just exit after popping up the error box.
      SLMessage.Error( null, "Sybase classes not found." +
                       "\nCheck CLASSPATH and restart." );
      exit();
    }
    catch( SQLException e )
    {
      String encryptedPassword;

      try
      {
        String plainTextPassword = "";

        encryptedPassword = encryptString( dbProperties.getProperty( SLDatabaseProperties.PASSWORD ) );

	setPassword( encryptedPassword );
	getDataServerProperties( dbSource ).setPassword( encryptedPassword );

	getDBConnection( dbSource );

        doPostLogin();

        IMSPasswordChange = false;
        if( getAppComponent( "IMS_USER", true ) ) // DAW 26Jul2004
        {
          Util.log( "DoLoginWithRetry:  IMS User detected" );
          IMSEncryptedPassword = true ;
          useEncryption = true;
        }
        else
        {
          Util.log( "DoLoginWithRetry: Non-IMS User detected" );
          useEncryption = false;
          IMSEncryptedPassword = false ;

          return true;
        }

        return true;
      }

      catch( SQLException f )
      {

        dbProperties.setProperty( SLDatabaseProperties.PLAINTEXTPASSWORD, "" ); // DAW 7Jul2004
        dbProperties.setProperty( SLDatabaseProperties.PASSWORDENCRYPTED, "N" ); // DAW 7Jul2004
      }

      catch( ClassNotFoundException f )
      {
        //  If we catch this exception - most likely our CLASSPATH is not
        //  set up correctly. This is fatal and uncorrectable while the
        //  app is running - so just exit after popping up the error box.
        SLMessage.Error( null, "Sybase classes not found." +
                         "\nCheck CLASSPATH and restart." );
        exit();
      }
      catch( Exception ex )
      {
      }
      SLMessage.Error( null, "Login failed for user:\n<" +
                       ( ( getUserName() == null ) ? "null" : getUserName() ) + ">\n" +
                       "Letters in passwords must be typed using the correct case.\n" +
                       "Make sure that Caps Lock is not accidentally on." );

      return false;
      /*if( Global.getSingleWks() != null )
        exit();*/
    } // Try/Catch for SQL Exception from initial doLogin
    catch( Exception e )
    {
    }
    return false;
  }

  public static void doPostLogin()
  {
    if( getLogWriter() == null && getLogStream() == null )
      openLogFile( null );

    try
    {
      arguments.logArguments();
    }
    catch( IOException ex )
    {}

    if( location == null )
      Util.error( "Location not specified...   ( -L )" );
    else
      loadDefaults( location );

      // Set application date
    setApplicationDate();
  }

  private static boolean changePassword( String oldPassword )
  {
    String newPW = null;

    SLUserDBSQL mgr = new SLUserDBSQL();
    ChangePwdDialog changePwd = new ChangePwdDialog();
    changePwd.setModal( true );

    while( true )
    {
      changePwd.setVisible( true );
      changePwd.toFront();
      if( changePwd.getActionCode() == ChangePwdDialog.CANCEL )
      {
        try
        {
          getDBConnection( PRIMARY ).close();
        }
        catch( Exception e )
        {
          SLMessage.Error( null, e, "doInvolvedLogin" );
          return false;
        }
      }

      newPW = changePwd.getNewPassword();

      if( getAppComponent( "IMS_USER" ) )
      {
        if( IMSEncryptedPassword )
	{
          oldPassword = encryptString( oldPassword );
          useEncryption = true ;
          Util.log( "IMS User: Encrypt current password" ); // DAW 10Aug2004
        }
        else
        {
          useEncryption = false ;
        }

        Util.log( "IMS User: Encrypt new password" ); // DAW 10Aug2004
        newPW = encryptString( newPW );

        Util.log( "IMS User: Changing password from " + oldPassword + " to " + newPW );
      }

      try
      {
        mgr.changePassword( getDBConnection( PRIMARY ), oldPassword, newPW );
        Util.log( "Password on PRIMARY changed successfully" );
      }
      catch( Exception ex ) //SQLException and SLPasswordException
      {
        SLMessage.Error( changePwd, ex, "Changing Password",
                         "Could not change password: " + ex.getMessage() );
        return false;
      }

      if( isArchiveConnectionUp() )
      {
	Util.log( "ARCHIVE password changing from " + oldPassword + " to " + newPW );
	try
	{
          mgr.changePassword( getArchiveDBConnection(), oldPassword, newPW ); // DAW 24Aug2004
          SLMessage.Info( changePwd, "Password was changed successfully." );
          break;
        }
	catch( Exception ex ) //SQLException and SLPasswordException
	{
	  try
	  {
	    mgr.changePassword( getDBConnection( PRIMARY ), newPW, oldPassword );

	    SLMessage.Error( changePwd, ex, "Changing Password",
			     "Could not change password on Archive server,\nchanged main server password back to the original.\nError: " +
			     ex.getMessage() );
	    setPassword( oldPassword );
	  }
	  catch( Exception x )
	  {
	    SLMessage.Error( changePwd, x, "Changing Password",
			     "Could not change password on Archive server,\nreturn to the original password on main server failed:\n" +
			     x.getMessage() );
	  }

	  return false;
	}
      }
      else
      {
	//  If the archive connection is not available we can't change the password - return false
	//  but set the new password in our PRIMARY db properties
	setPassword( newPW );
	return false;
      }
    }

    //  Entire change password sequence was successful so set the new password in our PRIMARY db properties
    setPassword( newPW );

    return true;
  }
}

